package com.aptemo.webetek.server;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import com.aptemo.webetek.client.enums.EnumUserRole;
import com.aptemo.webetek.client.exceptions.BackendException;
import com.aptemo.webetek.client.exceptions.WebetekLoginException;
import com.aptemo.webetek.client.exceptions.BackendException.EErrorCodes;
import com.aptemo.webetek.server.data.PMF;
import com.aptemo.webetek.server.data.UserGroup;
import com.aptemo.webetek.server.data.WebetekUser;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;

public class CommonService
{
	private static final Logger	log			= Logger.getLogger(CommonService.class.getName());

	private UserService			userService	= UserServiceFactory.getUserService();

	public void checkLogin() throws WebetekLoginException
	{
		if (!userService.isUserLoggedIn())
		{
			throw new WebetekLoginException("Not logged in", userService.createLoginURL(""));
		}
	}

	public void checkAdmin() throws BackendException
	{
		if (!userService.isUserAdmin())
		{
			throw new BackendException(EErrorCodes.NOT_ADMIN);
		}
	}

	public void sendEmail(String fromEmail, String toEmail, String ccEmail, String subject, String content) throws BackendException
	{
		// 
		Properties props = new Properties();
		Session session = Session.getDefaultInstance(props, null);

		// http://127.0.0.1:8888/webetek/invite?id=agd3ZWJldGVrciALEglVc2VyR3JvdXAYXwwLEgtXZWJldGVrVXNlchhtDA
		String msgBody = content;

		try
		{
			log.info("Sending email to: " + toEmail + ", from: " + fromEmail + ", subject: " + subject);

			Message msg = new MimeMessage(session);
			msg.setFrom(new InternetAddress(fromEmail));

			// extract recipients...
			String[] tos = toEmail.split(",");
			for (int i = 0; i < tos.length; i++)
			{
				msg.addRecipient(Message.RecipientType.TO, new InternetAddress(tos[i]));
			}

			if (ccEmail != null && !ccEmail.isEmpty())
			{
				msg.addRecipient(Message.RecipientType.CC, new InternetAddress(ccEmail));
			}
			msg.setSubject(subject);
			msg.setText(msgBody);

			Transport.send(msg);

		}
		catch (AddressException e)
		{
			log.severe(e.getLocalizedMessage());
			throw new BackendException(EErrorCodes.WRONG_EMAIL_ADDRESS);
		}
		catch (MessagingException e)
		{
			log.severe(e.getLocalizedMessage());
			throw new BackendException(EErrorCodes.CANNOT_SEND_EMAIL);
		}
	}

	public List<WebetekUser> getUser(PersistenceManager pm, String email)
	{
		Query query = pm.newQuery(WebetekUser.class);
		query.setFilter("email == '" + email + "'");
		List<WebetekUser> users = (List<WebetekUser>) pm.newQuery(query).execute();

		query.closeAll();
		return users;
	}

	public List<WebetekUser> getUser(PersistenceManager pm, UserService userService)
	{
		User user = userService.getCurrentUser();
		if (user != null)
		{
			return getUser(pm, user.getEmail());
		}
		return new ArrayList<WebetekUser>();
	}

	public WebetekUser getUser(PersistenceManager pm, UserService userService, UserGroup team)
	{
		if (team == null)
		{
			return null;
		}

		User user = userService.getCurrentUser();
		if (user != null)
		{
			String currentUserEmail = user.getEmail();
			// WebetekUser player =
			// checkEmailMatch(currentUserEmail.toLowerCase(),
			// team.getPlayers());

			Query query = pm.newQuery(WebetekUser.class);
			query.setFilter("parentKey == :p1 && email == :p2");
			List<WebetekUser> players = (List<WebetekUser>) query.execute(team.getKey(), currentUserEmail);

			// TODO: try to remove '.'
			// String[] parts = currentUserEmail.split("@");
			// if (null == player && (parts.length > 1) &&
			// (parts[0].contains(".")))
			// {
			// String strippedEmail = parts[0].replace(".", "");
			// return checkEmailMatch(strippedEmail, team.getPlayers());
			// }
			if (players.isEmpty())
			{
				return null;
			}

			return players.get(0);
		}
		return null;
	}

	private WebetekUser checkEmailMatch(String email, Set<WebetekUser> players)
	{
		for (WebetekUser player : players)
		{
			if (player.getEmail().equalsIgnoreCase(email))
			{
				return player;
			}
		}
		return null;
	}

	public WebetekUser getUser(PersistenceManager pm, UserGroup team)
	{
		return getUser(pm, UserServiceFactory.getUserService(), team);
	}

	public UserGroup extractTeam(String teamId, PersistenceManager pm) throws BackendException
	{
		if (null == teamId || teamId.isEmpty())
		{
			// throw new BackendException(EErrorCodes.INVALID_ID);
			return null;
		}

		Key key = KeyFactory.stringToKey(teamId);
		if (null == key)
		{
			throw new BackendException(EErrorCodes.INVALID_ID);
		}

		UserGroup team = pm.getObjectById(UserGroup.class, key);
		return team;
	}

	public WebetekUser getCurrentUser(String teamId) throws BackendException
	{
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try
		{
			UserGroup team = extractTeam(teamId, pm);

			return getUser(pm, team);
		}
		finally
		{
			pm.close();
		}
	}

	public boolean isTeamEditor(PersistenceManager pm, UserGroup team) throws BackendException
	{
		WebetekUser user = this.getUser(pm, userService, team);
		if (userService.isUserAdmin())
		{
			return true;
		}
		if (user == null || user.getRole() != EnumUserRole.EDITOR)
		{
			throw new BackendException(EErrorCodes.NOT_TEAM_EDITOR);
		}
		return true;
	}

	public boolean isTeamEditor(String teamId) throws BackendException
	{
		return isTeamEditor(teamId, null);
	}

	public boolean isTeamEditor(String teamId, String email) throws BackendException
	{
		if (userService.isUserAdmin())
		{
			return true;
		}
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try
		{
			UserGroup team = extractTeam(teamId, pm);

			WebetekUser user;
			if (email == null || email.isEmpty())
			{
				user = getUser(pm, team);
			}
			else
			{
				user = getUser(pm, teamId, email);

			}

			if (user != null && user.getRole() == EnumUserRole.EDITOR)
			{
				return true;
			}
			return false;
		}
		finally
		{
			pm.close();
		}
	}

	private WebetekUser getUser(PersistenceManager pm, String teamId, String email)
	{
		Query query = pm.newQuery(WebetekUser.class);
		try
		{

			Key teamKey = KeyFactory.stringToKey(teamId);
			query.setFilter("email == '" + email + "' && parentKey == :p1");
			List<WebetekUser> users = (List<WebetekUser>) pm.newQuery(query).execute(teamKey);
			if (users.isEmpty())
			{
				return null;
			}
			return users.get(0);
		}
		finally
		{
			query.closeAll();
		}
	}

	public boolean isTeamMember(String teamId) throws BackendException
	{
		return isTeamMember(teamId, userService.getCurrentUser().getEmail());
	}

	public boolean isTeamMember(String teamId, String email) throws BackendException
	{
		// if (userService.isUserAdmin())
		// {
		// return true;
		// }
		// 
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try
		{
			WebetekUser user = getUser(pm, teamId, email);
			return user == null ? false : true;
		}
		finally
		{
			pm.close();
		}
	}

}
